package com.skt.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.skt.domain.DTO.request.MerchantOrderQueryRequest;
import com.skt.domain.ENUM.AccountStatus;
import com.skt.domain.ENUM.UserRole;
import com.skt.domain.PO.Costume;
import com.skt.domain.PO.RentalOrder;
import com.skt.domain.PO.RentalOrderItem;
import com.skt.domain.PO.User;
import com.skt.domain.VO.RentalOrderVO;
import com.skt.exception.AuthErrorCode;
import com.skt.exception.AuthException;
import com.skt.exception.OrderErrorCode;
import com.skt.exception.OrderException;
import com.skt.mapper.*;
import com.skt.result.PageResult;
import com.skt.security.LoginUser;
import com.skt.service.MerchantOrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class MerchantOrderServiceImpl extends ServiceImpl<RentalOrderMapper, RentalOrder> implements MerchantOrderService {

    private final UserMapper userMapper;
    private final CostumeMapper costumeMapper;
    private final RentalOrderItemMapper rentalOrderItemMapper;
    private final RentalOrderMapper rentalOrderMapper;

    /**
     * 查询商家订单列表
     * 根据当前登录商家 ID 及查询条件（状态、起止日期范围等）进行筛选。
     *
     * @param queryRequest 查询参数，包含分页信息及过滤条件
     * @return 分页结果，包含订单主信息及其明细项
     */
    @Override
    public PageResult<RentalOrderVO> MerchantOrderQueryRequest(MerchantOrderQueryRequest queryRequest) {
        // 1. 获取当前登录商家的用户 ID，并校验其权限
        Long currentUserId = getCurrentUserId();

        // 2. 校验请求中的日期范围和状态参数是否合法
        validateDateRange(queryRequest);

        // 3. 构建 MyBatis-Plus 分页对象，用于后续数据库分页查询
        Page<RentalOrder> page = new Page<>(queryRequest.getPageNum(), queryRequest.getPageSize());

        // 4. 构造动态查询条件并执行分页查询：
        //    - 限定为当前商家的订单
        //    - 按状态、开始/结束日期范围（可选）过滤
        //    - 按创建时间倒序排列
        IPage<RentalOrder> orderPage = this.lambdaQuery()
                .eq(RentalOrder::getMerchantId, currentUserId)
                .eq(queryRequest.getStatus() != null, RentalOrder::getStatus, queryRequest.getStatus())
                .ge(queryRequest.getStartDateFrom() != null, RentalOrder::getStartDate, queryRequest.getStartDateFrom())
                .le(queryRequest.getStartDateTo() != null, RentalOrder::getStartDate, queryRequest.getStartDateTo())
                .ge(queryRequest.getEndDateFrom() != null, RentalOrder::getEndDate, queryRequest.getEndDateFrom())
                .le(queryRequest.getEndDateTo() != null, RentalOrder::getEndDate, queryRequest.getEndDateTo())
                .orderByDesc(RentalOrder::getCreatedAt)
                .page(page);

        // 5. 将查到的原始订单记录转换为前端所需的 VO 对象（含明细和服装名称）
        List<RentalOrderVO> vos = buildRentalOrderVOs(orderPage.getRecords());

        // 6. 封装分页结果并返回
        return new PageResult<>(
                orderPage.getCurrent(),   // 当前页码
                orderPage.getSize(),      // 每页大小
                orderPage.getTotal(),     // 总记录数
                vos                       // 转换后的 VO 列表
        );
    }


    /**
     * 确认发货
     * @param orderId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void shipOrder(Long orderId) {
        // 1. 获取当前用户ID
        Long currentUserId = getCurrentUserId();

        // 2. 订单归属与存在性校验并验证订单状态
        RentalOrder order = validateOrderIsExists(orderId, currentUserId);

        // 3. 验证订单状态
        validateOrderStatusShip(order);

        // 4. 执行发货操作
        confirmShipment(order);
    }

    /**
     * 确认归还
     * @param orderId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void returnOrder(Long orderId) {
        // 1. 获取用户ID
        Long currentUserId = getCurrentUserId();

        // 2. 订单归属与存在性校验并验证订单状态
        RentalOrder order = validateOrderIsExists(orderId, currentUserId);

        // 3. 验证订单状态
        validateOrderStatusReturn(order);

        // 4. 执行归还操作
        confirmReturn(order);
    }

    /**
     * 执行归还操作
     * @param order
     */
    private void confirmReturn(RentalOrder order) {
        int updated = rentalOrderMapper.update(null,
                Wrappers.<RentalOrder>lambdaUpdate()
                        .set(RentalOrder::getStatus, 5)
                        .set(RentalOrder::getUpdatedAt, LocalDateTime.now())
                        .eq(RentalOrder::getId, order.getId())
                        .eq(RentalOrder::getStatus, 4));

        if (updated == 0) {
            throw OrderException.of(OrderErrorCode.ORDER_ALREADY_RETURNED);
        }
    }

    /**
     * 验证订单状态(归还) status = 4
     * @param order
     */
    private void validateOrderStatusReturn(RentalOrder order) {
        if (order.getStatus() != 4) {
            throw OrderException.of(OrderErrorCode.ORDER_CANNOT_BE_RETURNED);
        }
    }

    /**
     * 执行发货操作
     * @param order
     */
    private void confirmShipment(RentalOrder order) {
        // 仅当当前状态为 2 时才更新为 3
        int updated = rentalOrderMapper.update(null,
                Wrappers.<RentalOrder>lambdaUpdate()
                        .set(RentalOrder::getStatus, 3)
                        .set(RentalOrder::getUpdatedAt, LocalDateTime.now()) // 记录修改时间
                        .eq(RentalOrder::getId, order.getId())
                        .eq(RentalOrder::getStatus, 2)
        );

        if (updated == 0) {
            // 虽然前面校验过，但并发下可能已被修改
            throw OrderException.of(OrderErrorCode.ORDER_CANNOT_BE_SHIPPED, "订单状态已变更，无法发货");
        }
    }

    /**
     * 订单归属与存在性校验
     * @param orderId
     * @param merchantId
     */
    private RentalOrder validateOrderIsExists(Long orderId, Long merchantId) {
        RentalOrder order = rentalOrderMapper.selectById(orderId);
        if (order == null) {
            throw OrderException.of(OrderErrorCode.ORDER_NOT_FOUND);
        }

        if (!order.getMerchantId().equals(merchantId)) {
            throw OrderException.of(OrderErrorCode.ORDER_ACCESS_DENIED);
        }

        return order;
    }

    /**
     * 验证订单状态(发货) status = 2
     * @param order
     */
    private void validateOrderStatusShip(RentalOrder order) {
        if (order.getStatus() != 2) {
            throw OrderException.of(OrderErrorCode.ORDER_CANNOT_BE_SHIPPED);
        }
    }

    /**
     * 将原始订单列表转换为前端所需的 VO 列表，包含订单明细和服装信息。
     *
     * @param orders 原始订单实体列表
     * @return 转换后的 RentalOrderVO 列表
     */
    private List<RentalOrderVO> buildRentalOrderVOs(List<RentalOrder> orders) {
        if (CollectionUtils.isEmpty(orders)) {
            return Collections.emptyList();
        }

        // 提取所有订单 ID，用于批量查询明细
        List<Long> orderIds = orders.stream()
                .map(RentalOrder::getId)
                .collect(Collectors.toList());

        // 批量查询关联的订单明细项
        List<RentalOrderItem> allItems = rentalOrderItemMapper.selectList(
                Wrappers.<RentalOrderItem>lambdaQuery()
                        .in(RentalOrderItem::getOrderId, orderIds)
        );

        // 按订单 ID 分组，便于后续快速查找
        final Map<Long, List<RentalOrderItem>> orderIdToItemsMap = allItems.stream()
                .collect(Collectors.groupingBy(RentalOrderItem::getOrderId));

        // 提取所有服装 ID，用于批量查询服装名称
        Set<Long> costumeIds = allItems.stream()
                .map(RentalOrderItem::getCostumeId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        // 批量查询服装信息并构建 ID -> Costume 的映射
        final Map<Long, Costume> costumeMap;
        if (!costumeIds.isEmpty()) {
            List<Costume> costumes = costumeMapper.selectBatchIds(costumeIds);
            costumeMap = costumes.stream()
                    .collect(Collectors.toMap(Costume::getId, c -> c, (c1, c2) -> c1));
        } else {
            costumeMap = Collections.emptyMap();
        }

        // 转换每个订单为主 VO + 明细 VO 列表
        return orders.stream().map(order -> {
            RentalOrderVO vo = new RentalOrderVO();
            vo.setId(order.getId());
            vo.setOrderNo(order.getOrderNo());
            vo.setStartDate(order.getStartDate());
            vo.setEndDate(order.getEndDate());
            vo.setRemark(order.getRemark());
            vo.setTotalDays(order.getTotalDays());
            vo.setTotalAmount(order.getTotalAmount());
            vo.setStatus(order.getStatus());
            vo.setCreatedAt(order.getCreatedAt());
            vo.setStatusDesc(getStatusDesc(order.getStatus()));

            // 填充订单明细
            List<RentalOrderItem> items = orderIdToItemsMap.get(order.getId());
            if (!CollectionUtils.isEmpty(items)) {
                List<RentalOrderVO.OrderItemVO> itemVOs = items.stream().map(item -> {
                    RentalOrderVO.OrderItemVO itemVO = new RentalOrderVO.OrderItemVO();
                    itemVO.setCostumeId(item.getCostumeId());
                    itemVO.setQuantity(item.getQuantity());
                    itemVO.setDailyPrice(item.getDailyPrice());

                    // 计算单项小计：日租金 × 数量 × 租赁总天数
                    if (item.getDailyPrice() != null && item.getQuantity() != null && order.getTotalDays() != null) {
                        BigDecimal subtotal = item.getDailyPrice()
                                .multiply(BigDecimal.valueOf(item.getQuantity()))
                                .multiply(BigDecimal.valueOf(order.getTotalDays()));
                        itemVO.setSubtotal(subtotal.setScale(2, BigDecimal.ROUND_HALF_UP));
                    }

                    // 关联服装名称
                    Costume costume = costumeMap.get(item.getCostumeId());
                    if (costume != null) {
                        itemVO.setCostumeName(costume.getName());
                    }

                    return itemVO;
                }).collect(Collectors.toList());
                vo.setItems(itemVOs);
            } else {
                vo.setItems(Collections.emptyList());
            }

            return vo;
        }).collect(Collectors.toList());
    }

    /**
     * 根据订单状态码返回对应的中文描述。
     *
     * @param status 订单状态码
     * @return 状态描述文本
     */
    private String getStatusDesc(Integer status) {
        return switch (status) {
            case 1 -> "待支付";
            case 2 -> "已支付";
            case 3 -> "已发货";
            case 4 -> "已取货";
            case 5 -> "已归还";
            case 6 -> "已取消";
            default -> "未知状态";
        };
    }

    /**
     * 校验查询请求中的日期范围是否合法。
     *
     * @param request 查询请求对象
     */
    private void validateDateRange(MerchantOrderQueryRequest request) {
        if (request.getStatus() != null && (request.getStatus() < 1 || request.getStatus() > 6)) {
            throw OrderException.of(OrderErrorCode.INVALID_ORDER_STATUS_FILTER);
        }
        if (request.getStartDateFrom() != null && request.getStartDateTo() != null &&
                request.getStartDateTo().isBefore(request.getStartDateFrom())) {
            throw OrderException.of(OrderErrorCode.START_DATE_RANGE_INVALID);
        }
        if (request.getEndDateFrom() != null && request.getEndDateTo() != null &&
                request.getEndDateTo().isBefore(request.getEndDateFrom())) {
            throw OrderException.of(OrderErrorCode.END_DATE_RANGE_INVALID);
        }
    }

    /**
     * 获取当前认证用户的 ID，并校验其是否为有效商家。
     *
     * @return 当前商家用户 ID
     * @throws AuthException 若用户未登录、无效或非商家角色
     */
    private Long getCurrentUserId() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth == null || !auth.isAuthenticated() || !(auth.getPrincipal() instanceof LoginUser loginUser)) {
            throw AuthException.of(AuthErrorCode.TOKEN_INVALID);
        }

        Long userId = loginUser.getUserId();
        if (userId == null) {
            throw AuthException.of(AuthErrorCode.USER_ID_INVALID);
        }

        // 校验用户状态和角色
        User user = userMapper.selectById(userId);
        if (user == null ||
                user.getAccountStatus() != AccountStatus.ENABLED ||
                user.getRole() != UserRole.MERCHANT) {
            throw AuthException.of(AuthErrorCode.PERMISSION_DENIED);
        }

        return userId;
    }
}